package com.unione.unione_voice

import android.text.TextUtils
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.alibaba.fastjson.JSON
import com.blankj.utilcode.util.ToastUtils
import com.iflytek.aiui.AIUIAgent
import com.iflytek.aiui.AIUIConstant
import com.iflytek.aiui.AIUIEvent
import com.iflytek.aiui.AIUIListener
import com.unione.unione_base.BaseApplication
import com.unione.unione_voice.engine.AiuiEngine
import com.unione.unione_voice.engine.EngineConstants
import com.unione.unione_voice.engine.WakeupEngine
import com.unione.unione_voice.engine.WakeupListener
import com.unione.unione_voice.recorder.AudioRecorder
import com.unione.unione_voice.recorder.RecorderFactory
import com.unione.unione_voice.recorder.SystemRecorder
import com.unione.unione_voice.utils.CopyAssetsUtils
import com.unione.unione_voice.utils.FileUtil
import com.unione.unione_voice.utils.GuidUtil
import com.unione.unione_voice.utils.StreamingAsrUtil
import com.unione.unione_voice.utils.senselessWordUtil
import java.nio.charset.StandardCharsets

object AIUIManager {

    private var mAIUIAgent: AIUIAgent? = null
    private var recorder: AudioRecorder? = null

    val liveDataAIUIQuestion = MutableLiveData<String>()
    val liveDataAIUIAnswer = MutableLiveData<String>()

    const val TAG = "AIUIManager"

    init {
        CopyAssetsUtils.portingFile(BaseApplication.getContext())
    }


    private var wakeupListener: WakeupListener? = WakeupListener { angle, beam, score, keyWord ->
        //唤醒时停止播放tts
        AiuiEngine.TTS_stop()
    }

    /**
     * AIUI 回调信息处理
     */
    private var aiuiListener: AIUIListener? = AIUIListener { event: AIUIEvent ->
        when (event.eventType) {
            AIUIConstant.EVENT_CONNECTED_TO_SERVER -> {
                val uid = event.data.getString("uid")
                Log.i(TAG, "已连接服务器,uid：$uid")
            }

            AIUIConstant.EVENT_SERVER_DISCONNECTED -> Log.i(TAG, "与服务器断开连接")

            AIUIConstant.EVENT_WAKEUP -> Log.i(TAG, "进入识别状态")

            AIUIConstant.EVENT_RESULT -> {
                //处理语音合成结果
                if (event.info.contains("\"sub\":\"tts")) {
                    // 云端tts结果
                    //保存云端或离线tts音频文件，用于离线播放
                    if (EngineConstants.saveTTS) {
                        val audio =
                            event.data.getByteArray("0") //tts音频数据，16k，16bit格式
                        if (audio != null) {
                            FileUtil.writeFile(audio, "/sdcard/tts.pcm")
                        }
                    }

                    //如果使用sdk的播放器合成，可以不用解析tts
                    return@AIUIListener
                    //开发者自己用播放器来合成
//                    byte[] audio=event.data.getByteArray("0");//tts音频数据，16k，16bit格式
//                    超过500ms静音，认为是无效音频，进行过滤
//                    byte[] filteredAudio=TtsFilterUtil.filter(audio,500);
                }
                //处理识别结果
                if (event.info.contains("\"sub\":\"iat")) {
                    // 听写结果 iat
                    val cntJson = JSON.parseObject(
                        String(event.data.getByteArray("0")!!, StandardCharsets.UTF_8)
                    ) ?: return@AIUIListener
                    //                    Log.d(TAG, "cntJson" + cntJson);
                    val text = cntJson.getJSONObject("text")
                    //识别结果
                    val asrResult: String = StreamingAsrUtil.processIATResult(text)
                    //最终识别结果
                    if (text.getBoolean("ls")) {
                        Log.d(TAG, "识别结果=$asrResult")
                        //sid是每次交互的id，提供给讯飞可以查云端音频和结果
                        val sid = event.data.getString("sid")
                        Log.i(TAG, "sid=$sid")
                    }
                } else if (event.info.contains("\"sub\":\"nlp")) {
                    // 语义结果 nlp
                    //在线语义结果,rc=0(语义理解成功) rc=1(语义输入有问题) rc=2(内部错误)  rc=3(nlg有问题)   rc=4(说法未命中技能)
                    val cntJson = JSON.parseObject(
                        String(
                            event.data.getByteArray("0")!!,
                            StandardCharsets.UTF_8
                        )
                    )
                    val nlpResult = cntJson.getJSONObject("intent")
                    //nlp无结果不处理
                    if (nlpResult.isEmpty()) {
                        return@AIUIListener
                    }
                    /*判断请求类型，执行不同的逻辑。说明文档：https://www.yuque.com/iflyaiui/zzoolv/xp3trb
                        *1. 3种nlp请求执行逻辑不同
                        *   <1>语音  <2>文本请求-触屏  <3>文本请求-后台-不显示给用户
                        *2. event.data.getString("stream_id")区分语音和文本请求
                        *  语音请求 stream_id.startsWith("audio")
                        *  文本请求 stream_id.startsWith("text")
                        *3. event.data.getString("tag")区分文本请求的不同类型，tag是客户自定义的
                        *  文本请求-触屏 event.data.getString("tag").equals("text-touch")
                        *  文本请求-后台 event.data.getString("tag").equals("text-tag")
                        */
//                    String tag = event.data.getString("tag");
//                    Log.i(TAG, "tag==" + tag);
//                    if (event.data.getString("stream_id").startsWith("text")) {
//                        //文本请求结束后，不会自动重置状态，因此要手动
//                        if (AiuiUtils.wakeupType == WAKEUPTYPE_TEXT) {
//                            AiuiUtils.mAIUIState = AIUIConstant.STATE_READY;
//                        }
//                        if (event.data.getString("tag").equals("text-tag")) {
//                            Log.i(TAG, "文本请求-后台的nlp回调");
//                        } else if (event.data.getString("tag").equals("text-touch")) {
//                            Log.i(TAG, "文本请求-触屏的nlp回调");
//                        }
//                    } else if (event.data.getString("stream_id").startsWith("audio")) {
//                        Log.i(TAG, "语音请求的nlp回调");
//                    }

                    //识别结果
                    //如果只判断asr结果中的无意义词，若nlp先返回就可能被错误判断为无意义词
                    val asrResult = nlpResult.getString("text")
                    EngineConstants.meaningful =
                        senselessWordUtil.isMeaningful_filter1word(asrResult)
                    //无意义词不处理
                    if (!EngineConstants.meaningful) {
//                        senselessWordUtil.nonsenseSid = event.data.getString("sid");
//                        Log.i(TAG, "无意义请求的sid=" + senselessWordUtil.nonsenseSid);
                        return@AIUIListener
                    }
                    liveDataAIUIQuestion.value = asrResult
                    //云端的nlp回答结果，调用tts
                    val answerObject = nlpResult.getJSONObject("answer")
                    if (answerObject != null) {
                        val answer = answerObject.getString("text")
                        //tts合成方式1：aiui平台开启云端语义后自动合成，代码不用调用
                        //tts合成方式2：设备主动请求云端合成(推荐)，下方为方式2
                        /*val params = StringBuffer()
                        params.append("vcn=x4_lingxiaoying_em_v2") //发音人，所有发音人请查看https://www.yuque.com/iflyaiui/zzoolv/iwxf76/edit#ZvJ9r
                        params.append(",speed=55") //语速，取值范围[0,100]
                        params.append(",pitch=50") //音调，取值范围[0,100]
                        params.append(",volume=55") //音量，取值范围[0,100]
                        AiuiEngine.TTS_start(answer, params)*/
                        liveDataAIUIAnswer.value = answer
                    }
                    Log.i(TAG, "nlp result :$nlpResult")
                } else if (event.info.contains("\"sub\":\"itrans")) {
                    // 翻译结果 itrans
                    val cntJson = JSON.parseObject(
                        String(
                            event.data.getByteArray("0")!!,
                            StandardCharsets.UTF_8
                        )
                    )
                    if (cntJson != null) {
                        val tmp = cntJson.getJSONObject("trans_result")
                        val src = tmp.getString("src")
                        val dst = tmp.getString("dst")
                    }
                } else if (event.info.contains("\"sub\":\"tpp")) {
                    // 后处理服务结果
                    val cntJson = JSON.parseObject(
                        String(event.data.getByteArray("0")!!, StandardCharsets.UTF_8)
                    )
                    if (cntJson != null) {
                        Log.i(TAG, "tpp后处理结果")
                        Log.i(TAG, cntJson.toString())
                    }
                } else if (event.info.contains("\"sub\": \"esr_pgs\"")) {
                    //离线识别中间结果 esr 代表离线
                    val cntJson = JSON.parseObject(
                        String(
                            event.data.getByteArray("0")!!,
                            StandardCharsets.UTF_8
                        )
                    )
                } else if (event.info.contains("\"sub\": \"esr_fsa\"")) {
                    //离线命令词最终结果
                    val cntJson = JSON.parseObject(
                        String(
                            event.data.getByteArray("0")!!,
                            StandardCharsets.UTF_8
                        )
                    )
                    if (cntJson != null) {
                        if (TextUtils.isEmpty(cntJson.toString())) {
                            return@AIUIListener
                        }
                        // 解析得到语义结果
                        val resultStr = cntJson.getString("intent")
                    }
                } else if (event.info.contains("\"sub\": \"esr_iat\"")) {
                    //离线识别最终结果
                    val cntJson = JSON.parseObject(
                        String(event.data.getByteArray("0")!!, StandardCharsets.UTF_8)
                    )
                    if (cntJson != null) {
                        if (TextUtils.isEmpty(cntJson.toString())) {
                            return@AIUIListener
                        }
                        // 解析得到语义结果
                        val resultStr = cntJson.getString("intent")
                    }
                }
            }

            AIUIConstant.EVENT_ERROR -> when (event.arg1) {
                11217 -> {
                    //11217报错时，aiui没有正常初始化，因此进行destroy()
                    AiuiEngine.destroy()
                    //11217可能是一个sn绑定了2台设备(例如ota升级)，因此初始化2次保证ota后正常，禁止循环初始化
                    if (EngineConstants.firstInit) {
                        initAIUI()
                        EngineConstants.firstInit = false //避免循环初始化
                        Log.d(TAG, "错误码11217,重新初始化一次")
                    }
                }

                else -> {
                    //("错误码: " + event.arg1)
                    //("错误信息:" + event.info)
                    //( """${"解决方案:" + ErrorCode.getError(event.arg1)} 错误解决详情参考：https://www.yuque.com/iflyaiui/zzoolv/igbuol""" )
                }
            }

            AIUIConstant.EVENT_VAD -> if (AIUIConstant.VAD_BOS == event.arg1) {
                Log.i(TAG, "vad_bos,开始说话")
            } else if (AIUIConstant.VAD_BOS_TIMEOUT == event.arg1) {
                Log.i(TAG, "vad timeout,不说话,前端点超时")
            } else if (AIUIConstant.VAD_EOS == event.arg1) {
                Log.i(TAG, "vad eos,结束说话")
            } else if (AIUIConstant.VAD_VOL == event.arg1) {
//                    Log.i(TAG, "vad vol,说话音量:" + event.arg2);
            }

            AIUIConstant.EVENT_SLEEP -> Log.i(TAG, "设备休眠")

            AIUIConstant.EVENT_START_RECORD -> Log.i(TAG, "开始录音")

            AIUIConstant.EVENT_STOP_RECORD -> Log.i(TAG, "停止录音")

            AIUIConstant.EVENT_STATE -> {
                EngineConstants.mAIUIState = event.arg1
                if (AIUIConstant.STATE_IDLE == EngineConstants.mAIUIState) {
                    // 闲置状态，AIUI未开启
                    Log.i(TAG, "aiui状态:STATE_IDLE")
                } else if (AIUIConstant.STATE_READY == EngineConstants.mAIUIState) {
                    // AIUI已就绪，等待唤醒
                    Log.i(TAG, "aiui状态:STATE_READY")
                } else if (AIUIConstant.STATE_WORKING == EngineConstants.mAIUIState) {
                    // AIUI工作中，可进行交互
                    Log.i(TAG, "aiui状态:STATE_WORKING")
                }
            }

            AIUIConstant.EVENT_TTS -> {
                when (event.arg1) {
                    AIUIConstant.TTS_SPEAK_BEGIN -> Log.i(TAG, "tts:开始播放")
                    AIUIConstant.TTS_SPEAK_PROGRESS -> {}
                    AIUIConstant.TTS_SPEAK_PAUSED -> Log.i(TAG, "tts:暂停播放")
                    AIUIConstant.TTS_SPEAK_RESUMED -> Log.i(TAG, "tts:恢复播放")
                    AIUIConstant.TTS_SPEAK_COMPLETED -> Log.i(TAG, "tts:播放完成")
                    else -> {}
                }
            }

            else -> {}
        }
    }


//    fun init() {
//        viewModelScope.launch {
//            CopyAssetsUtils.portingFile(BaseApplication.getContext())
//        }
//    }

    fun initAIUISdk() {
        //状态初始化
        EngineConstants.isRecording = false
        //TODO 开发者需要实现生成sn的代码，参考：https://www.yuque.com/iflyaiui/zzoolv/tgftb5
        //注意事项1: sn每台设备需要唯一！！！！WakeupEngine的sn和AIUI的sn要一致
        //注意事项2: 获取的值要保持稳定，否则会重复授权，浪费授权量
        var guid = ""
        if (TextUtils.isEmpty(GuidUtil.getFromFile(BaseApplication.getContext()))) {
            guid = GuidUtil.createGUID(BaseApplication.getContext())
            GuidUtil.setToFile(BaseApplication.getContext(), guid)
        } else {
            guid = GuidUtil.getFromFile(BaseApplication.getContext())
        }
        EngineConstants.serialNumber = guid
        //对音频的处理为降噪唤醒再送去识别,
        SystemRecorder.AUDIO_TYPE_ASR = false
        // 初始化AIUI
        initAIUI()
        //初始化wakeupEngine(降噪+唤醒)
        val initResult: Int = WakeupEngine.getInstance(wakeupListener)
        if (initResult == 0) {
            Log.i(TAG, "wakeupEngine初始化成功")
        } else {
            //错误解决详情参考：https://www.yuque.com/iflyaiui/zzoolv/igbuol"""
            Log.e(TAG, "wakeupEngine初始化失败")
        }
        //初始化录音
        if (recorder == null) {
            recorder = RecorderFactory.getRecorder()
        }
        if (recorder != null) {
            Log.i(TAG, "录音机初始化成功")
            startRecord()
        } else {
            Log.i(TAG, "录音机初始化失败")
        }

    }

    fun initAIUI() {
        // 初始化AIUI(识别+语义+合成）
        mAIUIAgent = AiuiEngine.getInstance(aiuiListener, "cfg/aiui.cfg")
        if (mAIUIAgent != null) {
            Log.i(TAG, "AIUI初始化成功")
            if (recorder != null) {

            }
        } else {
            Log.e(TAG, "AIUI初始化失败")
        }
    }


    fun startRecord() {
        if (recorder != null) {
            val ret = recorder!!.startRecord()
            if (0 == ret) {
                //("开启录音成功！")
            } else if (111111 == ret) {
                //("异常,AlsaRecorder is null ...")
            } else {
                ToastUtils.showLong("开启录音失败，请查看/dev/snd/下的设备节点是否有777权限！\nAndroid 8.0 以上需要暂时使用setenforce 0 命令关闭Selinux权限！")
                destroyRecord()
            }
        }
    }

    fun stopRecord() {
        if (recorder != null) {
            recorder!!.stopRecord()
        }
    }


    fun destroyRecord() {
        stopRecord()
        recorder = null
        Log.d(TAG, "destroy is Done!")
    }

    fun onDestroy() {
        if (EngineConstants.isRecording) {
            stopRecord()
        }
        //销毁唤醒引擎
        WakeupEngine.destroy()
        //销毁aiui
        AiuiEngine.destroy()
        if (wakeupListener != null) {
            wakeupListener = null
        }
        if (aiuiListener != null) {
            aiuiListener = null
        }
        if (recorder != null) {
            recorder!!.destroyRecord()
            recorder = null
        }
    }

}